home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / gui / infobox / infobox.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  41KB  |  1,160 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from util.vec import vector
  6. from util import linkify
  7. import protocols
  8. from interfaces import IInfoboxHTMLProvider
  9. import sys
  10. import wx
  11. from wx import RectPS, RectS, Point, CallLater, GetMouseState, FindWindowAtPointer, GetMousePosition, Size, PaintDC, BufferedPaintDC
  12. import warnings
  13. import wx.html as html
  14. from gui.capabilitiesbar import CapabilitiesBar
  15. from contacts.Contact import Contact
  16. from contacts.metacontacts import MetaContact
  17. from common.emailaccount import EmailAccount
  18. from social.network import SocialNetwork
  19. from gui import skin
  20. from gui.skin.skinobjects import SkinColor, Margins
  21. from gui.infobox.emailpanels import EmailList, Header
  22. from common import pref, setpref, profile
  23. from gui.buddylist import BuddyList
  24. from gui.windowfx import fadein
  25. from gui.toolbox import CopyToClipboard
  26. from gui.textutil import CopyFont, TagFont, default_font
  27. from util import Storage, Point2HTMLSize
  28. from gui.infobox.errorpanel import ErrorPanel
  29. from cgui import SimplePanel
  30. from gui.windowfx import ApplySmokeAndMirrors
  31. from common import prefprop
  32. from gui.toolbox import Monitor
  33. from gui import imwin
  34. from cgui import SplitImage4
  35. import wx.lib.wxpTag as wx
  36. from gui.windowfx import move_smoothly, resize_smoothly
  37. from gui.infobox.htmlgeneration import GetInfo
  38. from logging import getLogger
  39. log = getLogger('infobox')
  40. from common import bind
  41. import traceback
  42. from traceback import print_exc
  43. DEFAULT_INFOBOX_WIDTH = 330
  44. TRAY_TIMER_MS = 500
  45. from threading import currentThread
  46.  
  47. class ExpandoPanel(wx.Panel):
  48.     
  49.     def __init__(self, parent, infobox):
  50.         wx.Panel.__init__(self, parent, pos = (-300, -300))
  51.         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  52.         self.SetMinSize(wx.Size(20, 20))
  53.         self.infobox = infobox
  54.         Bind = self.Bind
  55.         Bind(wx.EVT_PAINT, self.OnPaint)
  56.         Bind(wx.EVT_LEFT_UP, self.OnLUp)
  57.         Bind(wx.EVT_LEFT_DCLICK, self.OnDClick)
  58.         Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
  59.         Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
  60.  
  61.     
  62.     def OnMouseEnter(self, event):
  63.         if not self.HasCapture():
  64.             self.CaptureMouse()
  65.         
  66.         self.Refresh(False)
  67.  
  68.     
  69.     def OnMouseLeave(self, event):
  70.         while self.HasCapture():
  71.             self.ReleaseMouse()
  72.         self.Refresh(False)
  73.  
  74.     
  75.     def OnPaint(self, event):
  76.         dc = BufferedPaintDC(self)
  77.         infobox = self.infobox
  78.         contact = infobox.metacontact[infobox.expandopanels.index(self)]
  79.         rect = RectS(self.Size)
  80.         iconsize = 16
  81.         padx = infobox.padding.x
  82.         i = None if infobox.account == contact else self.HasCapture()
  83.         infobox.contactbg[i].Draw(dc, rect)
  84.         dc.SetFont(infobox.headerfont)
  85.         dc.SetTextForeground(infobox.contactfontcolor[i])
  86.         name = contact.alias
  87.         servico = contact.serviceicon.Resized(iconsize)
  88.         statico = skin.get('statusicons.' + contact.status_orb).ResizedSmaller(iconsize)
  89.         dc.DrawBitmap(servico, 2 + padx, 2, True)
  90.         dc.DrawText(name, 21 + padx, 2)
  91.         dc.DrawBitmap(statico, (rect.width - 18) + (16 - statico.Size.width) // 2 - padx, rect.height // 2 - statico.Height // 2)
  92.  
  93.     
  94.     def OnDClick(self, event):
  95.         infobox = self.infobox
  96.         contact = infobox.metacontact[infobox.expandopanels.index(self)]
  97.         infobox.Hide()
  98.         imwin.begin_conversation(contact)
  99.  
  100.     
  101.     def OnLUp(self, event):
  102.         infobox = self.infobox
  103.         contact = infobox.metacontact[infobox.expandopanels.index(self)]
  104.         if self.HasCapture() and contact is not infobox.account:
  105.             infobox.SelectContact(contact)
  106.             infobox.cpanel.Refresh(False)
  107.         
  108.  
  109.  
  110.  
  111. class InfoBoxShowingTimer(wx.Timer):
  112.     
  113.     def __init__(self, infobox):
  114.         self.infobox = infobox
  115.         wx.Timer.__init__(self)
  116.  
  117.     
  118.     def Start(self, contact):
  119.         self.contact = contact
  120.         wx.Timer.Start(self, pref('infobox.show_delay', 1000), True)
  121.  
  122.     
  123.     def Notify(self):
  124.         i = self.infobox
  125.         if i is None or wx.IsDestroyed(i):
  126.             print >>sys.stderr, 'Infobox is dead but still getting notified!'
  127.             return None
  128.         
  129.         if i.FriendlyTouch():
  130.             i.ShowOnScreen()
  131.             i.InfoSync()
  132.             i.quickshow = True
  133.         
  134.  
  135.  
  136.  
  137. class InfoBoxHidingTimer(wx.Timer):
  138.     
  139.     def __init__(self, infobox):
  140.         self.infobox = infobox
  141.         wx.Timer.__init__(self)
  142.  
  143.     
  144.     def Notify(self):
  145.         i = self.infobox
  146.         if i is None or wx.IsDestroyed(i):
  147.             return None
  148.         
  149.         i.mouseouttimer.Stop()
  150.         i.showingtimer.Stop()
  151.         i.quickshow = False
  152.         i.Hide()
  153.  
  154.  
  155.  
  156. class InfoBoxTrayTimer(wx.Timer):
  157.     
  158.     def __init__(self, infobox):
  159.         wx.Timer.__init__(self)
  160.         self.infobox = infobox
  161.  
  162.     
  163.     def Notify(self):
  164.         
  165.         try:
  166.             mp = GetMousePosition()
  167.         except Exception:
  168.             return None
  169.  
  170.         import cgui as cgui
  171.         tray_rect = cgui.GetTrayRect()
  172.         i = self.infobox
  173.         if i is None or wx.IsDestroyed(i):
  174.             return None
  175.         
  176.         infobox_rect = i.Rect.Inflate(30, 30)
  177.         if not infobox_rect.Contains(mp) and not tray_rect.Contains(mp):
  178.             i.Hide()
  179.             self.Stop()
  180.         
  181.  
  182.  
  183.  
  184. class InfoBoxMouseOutTimer(wx.Timer):
  185.     
  186.     def __init__(self, infobox):
  187.         self.infobox = infobox
  188.         wx.Timer.__init__(self)
  189.         self.hider = InfoBoxHidingTimer(infobox)
  190.         self.noneweredown = False
  191.  
  192.     
  193.     def Start(self):
  194.         wx.Timer.Start(self, 200)
  195.         self.delayhide = False
  196.  
  197.     
  198.     def Notify(self):
  199.         
  200.         try:
  201.             mp = GetMousePosition()
  202.         except:
  203.             return None
  204.  
  205.         ms = GetMouseState()
  206.         if not ms.LeftDown() and ms.RightDown():
  207.             pass
  208.         button_down = ms.MiddleDown()
  209.         infobox = self.infobox
  210.         infobox_rect = infobox.Rect
  211.         inside = infobox_rect.Contains(mp)
  212.         ftouch = infobox.FriendlyTouch(mp)
  213.         if inside:
  214.             self.delayhide = True
  215.         elif ftouch:
  216.             self.delayhide = False
  217.         
  218.         hider = self.hider
  219.         if not inside and ftouch and infobox.capbar.cbar.overflowmenu.IsShown() and infobox.capbar.cto.menu.IsShown():
  220.             pass
  221.         if not infobox.capbar.cfrom.menu.IsShown() and self.noneweredown:
  222.             if button_down:
  223.                 hider.Start(1, True)
  224.             
  225.             if not hider.IsRunning():
  226.                 wap = wx.FindWindowAtPoint(mp)
  227.                 if wap is not None:
  228.                     if infobox.Parent.Top is wap.Top:
  229.                         pass
  230.                     inancestor = wap.Top is not wap
  231.                 else:
  232.                     inancestor = False
  233.                 None(hider.Start if self.delayhide or inancestor else 1, True)
  234.             
  235.         else:
  236.             self.noneweredown = False
  237.             if hider.IsRunning():
  238.                 hider.Stop()
  239.             
  240.         self.noneweredown = not button_down
  241.  
  242.  
  243.  
  244. class InfoBox(wx.Frame):
  245.     
  246.     def __dtor__(self):
  247.         for attr in ('mouseouttimer', 'showingtimer', 'hidingtimer', 'traytimer'):
  248.             obj = getattr(self, attr, None)
  249.             if obj is not None:
  250.                 obj.infobox = None
  251.                 obj.Stop()
  252.                 continue
  253.         
  254.  
  255.     
  256.     def __init__(self, parent):
  257.         wx.Frame.__init__(self, parent, -1, '', style = wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP | wx.NO_BORDER | wx.FRAME_TOOL_WINDOW)
  258.         self._cache = { }
  259.         self.friends = set()
  260.         self.quickshow = False
  261.         self.metacontact = None
  262.         self.account = None
  263.         self._doubleclickhide = False
  264.         self.expandopanels = []
  265.         self.mouseouttimer = InfoBoxMouseOutTimer(self)
  266.         self.showingtimer = InfoBoxShowingTimer(self)
  267.         self.hidingtimer = None
  268.         self.traytimer = InfoBoxTrayTimer(self)
  269.         timers = [
  270.             self.mouseouttimer,
  271.             self.showingtimer,
  272.             self.hidingtimer]
  273.         None((self.Bind, wx.EVT_WINDOW_DESTROY), (lambda e: [] if e.EventObject is self else None))
  274.         self.animationtimer = None
  275.         self.load_format()
  276.         self.pl = 0
  277.         self.pr = 0
  278.         self.force_corner = False
  279.         self.Show(False)
  280.         panel = self.panel = wx.Panel(self, pos = (-400, -400))
  281.         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  282.         self.UpdateSkin()
  283.         self.content = wx.BoxSizer(wx.VERTICAL)
  284.         sizer = panel.Sizer = wx.GridBagSizer()
  285.         sizer.SetEmptyCellSize(wx.Size(0, 0))
  286.         sizer.AddGrowableCol(1, 1)
  287.         sizer.AddGrowableRow(1, 1)
  288.         sizer.Add(self.content, (1, 1), flag = wx.EXPAND)
  289.         sizer.Add(wx.Size(self.framesize.left, self.framesize.top), (0, 0))
  290.         sizer.Add(wx.Size(self.framesize.right, self.framesize.bottom), (2, 2))
  291.         caps = self.capbar = CapabilitiesBar((self.panel,), (lambda : self.account), True, True)
  292.         for b in ('info', 'im', 'email', 'sms'):
  293.             caps.GetButton(b).Bind(wx.EVT_BUTTON, (lambda e, b = (b,): (self.Hide(), wx.CallAfter(self.account.imwin_mode, b))))
  294.         
  295.         import gui.pref.prefsdialog as gui
  296.         (caps.OnSendFiles,) += (lambda : (self.Hide(), self.account.send_file()))
  297.         (caps.OnSendFolder,) += (lambda : (self.Hide(), self.account.send_folder()))
  298.         (caps.OnViewPastChats,) += (lambda : (self.Hide(), self.account.view_past_chats()))
  299.         (caps, caps.OnAlert) += (lambda : (self.Hide(), gui.pref.prefsdialog.show('notifications')))
  300.         wx.CallAfter(caps.ShowToFrom, False)
  301.         wx.CallAfter(caps.ShowCapabilities, pref('infobox.showcapabilities', True))
  302.         self.content.Add(self.capbar, 0, wx.EXPAND)
  303.         self.eheader = Header(panel)
  304.         self.content.Add(self.eheader, 0, wx.EXPAND)
  305.         self.eheader.Show(False)
  306.         self.cpanel = wx.Panel(panel)
  307.         self.cpanel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  308.         self.cpanel.Sizer = wx.BoxSizer(wx.VERTICAL)
  309.         self.content.Add(self.cpanel, 1, wx.EXPAND)
  310.         self.elist = EmailList(panel)
  311.         self.content.Add(self.elist, 1, wx.EXPAND)
  312.         self.elist.Show(False)
  313.         self.errorpanel = ErrorPanel(panel)
  314.         self.content.Add(self.errorpanel, 1, wx.EXPAND)
  315.         self.errorpanel.Show(False)
  316.         panel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  317.         panel.Bind(wx.EVT_PAINT, self.OnPaint)
  318.         panel.Bind(wx.EVT_ERASE_BACKGROUND, (lambda e: pass))
  319.         panel.SetSize(wx.Size(DEFAULT_INFOBOX_WIDTH, DEFAULT_INFOBOX_WIDTH))
  320.         pbox.SetMaxWordLength(self.width - 85)
  321.         pbox.SetBorders(self.padding.x)
  322.         self.Bind(wx.EVT_SIZE, self.OnSize)
  323.         
  324.         def set_fonts(val):
  325.             self.profilebox.SetFonts(pref('infobox.fonts.normal', default_font().FaceName), pref('infobox.fonts.fixed', 'Courier New'))
  326.  
  327.         profile.prefs.link('infobox.fonts.normal', set_fonts, callnow = False, obj = self)
  328.         profile.prefs.link('infobox.fonts.fixed', set_fonts, obj = self)
  329.         self.profilebox.Bind(html.EVT_HTML_LINK_CLICKED, self.OnLinkClicked)
  330.         self.cpanel.Sizer.Add(self.profilebox, 1, wx.EXPAND)
  331.         wx.CallAfter(self.DoSizeMagic)
  332.  
  333.     
  334.     def CtrlCHandler(self):
  335.         CopyToClipboard(self.profilebox.SelectionToText())
  336.  
  337.     CtrlCHandler = bind('InfoBox.Copy')(CtrlCHandler)
  338.     
  339.     def do_focus(self):
  340.         for ctrl in (self.profilebox, self.elist, self.cpanel):
  341.             if ctrl.IsShownOnScreen():
  342.                 print 'focusing', ctrl
  343.                 self.ReallyRaise()
  344.                 ctrl.SetFocusFromKbd()
  345.                 break
  346.                 continue
  347.         
  348.  
  349.     
  350.     def load_format(self):
  351.         import syck as syck
  352.         
  353.         try:
  354.             
  355.             try:
  356.                 f = _[2]
  357.                 self.format = dict(syck.load(f))
  358.             finally:
  359.                 pass
  360.  
  361.         except:
  362.             self.format = { }
  363.             print_exc()
  364.  
  365.  
  366.     
  367.     def UpdateSkin(self):
  368.         s = skin.get
  369.         self.framesize = s('infobox.framesize', (lambda : Margins([
  370. 0,
  371. 0,
  372. 0,
  373. 0])))
  374.         self.padding = s('infobox.padding', (lambda : Point(2, 2)))
  375.         if hasattr(self, 'profilebox'):
  376.             self.profilebox.SetBorders(self.padding.x)
  377.         
  378.         self.headerfont = s('infobox.fonts.header', default_font)
  379.         self.headerfc = s('infobox.fontcolors.header', wx.BLACK)
  380.         self.headerhoverfc = s('infobox.fontcolors.contacthover', wx.BLACK)
  381.         self.headerselfc = s('infobox.fontcolors.contactselected', wx.BLACK)
  382.         titlefont = skin.get('infobox.fonts.title', default_font)
  383.         majorfont = skin.get('infobox.fonts.major', default_font)
  384.         minorfont = skin.get('infobox.fonts.minor', default_font)
  385.         linkfont = CopyFont(skin.get('infobox.fonts.link', default_font), underline = True)
  386.         h = self.htmlfonts = Storage()
  387.         h.header = self.headerfont
  388.         h.title = titlefont
  389.         h.major = majorfont
  390.         h.minor = minorfont
  391.         h.link = linkfont
  392.         h.headerfont = self.headerfont.FaceName
  393.         h.titlefont = titlefont.FaceName
  394.         h.majorfont = majorfont.FaceName
  395.         h.minorfont = minorfont.FaceName
  396.         h.linkfont = linkfont.FaceName
  397.         h.headersize = Point2HTMLSize(self.headerfont.PointSize)
  398.         h.titlesize = Point2HTMLSize(titlefont.PointSize)
  399.         h.majorsize = Point2HTMLSize(majorfont.PointSize)
  400.         h.minorsize = Point2HTMLSize(minorfont.PointSize)
  401.         h.linksize = Point2HTMLSize(linkfont.PointSize)
  402.         h.headerfc = self.headerfc.GetAsString(wx.C2S_HTML_SYNTAX)
  403.         h.titlefc = s('infobox.fontcolors.title', wx.BLACK).GetAsString(wx.C2S_HTML_SYNTAX)
  404.         h.majorfc = s('infobox.fontcolors.major', wx.BLACK).GetAsString(wx.C2S_HTML_SYNTAX)
  405.         h.minorfc = s('infobox.fontcolors.minor', (lambda : wx.Color(128, 128, 128))).GetAsString(wx.C2S_HTML_SYNTAX)
  406.         h.linkfc = s('infobox.fontcolors.link', wx.BLUE).GetAsString(wx.C2S_HTML_SYNTAX)
  407.         self.bg = s('infobox.frame', (lambda : SkinColor(wx.BLACK)))
  408.         self.barskin = s('capabilitiesbar', None)
  409.         self.contactbg = [
  410.             s('infobox.backgrounds.contact', (lambda : SkinColor(wx.Colour(128, 128, 128)))),
  411.             s('infobox.backgrounds.contacthover', (lambda : SkinColor(wx.GREEN))),
  412.             s('infobox.backgrounds.contactselected', (lambda : SkinColor(wx.WHITE)))]
  413.         self.contactfontcolor = [
  414.             s('infobox.fontcolors.contact', wx.BLACK),
  415.             s('infobox.fontcolors.contacthover', wx.BLACK),
  416.             s('infobox.fontcolors.contactselected', wx.BLACK)]
  417.         s = self.panel.Sizer
  418.         if s:
  419.             s.Detach(1)
  420.             s.Detach(1)
  421.             s.Add(wx.Size(self.framesize.left, self.framesize.top), (0, 0))
  422.             s.Add(wx.Size(self.framesize.right, self.framesize.bottom), (2, 2))
  423.         
  424.         if hasattr(self, 'capbar') and hasattr(self, 'cpanel'):
  425.             sizer = self.content
  426.             sizer.Detach(self.capbar)
  427.             sizer.Detach(self.cpanel)
  428.             sizer.Add(self.capbar, 0, wx.EXPAND)
  429.             sizer.Add(self.cpanel, 1, wx.EXPAND)
  430.         
  431.         self._cache.clear()
  432.  
  433.     
  434.     def OnPaint(self, event):
  435.         self.bg.Draw(PaintDC(self.panel), RectS(self.panel.Size))
  436.  
  437.     
  438.     def DoSizeMagic(self):
  439.         width = self.width
  440.         filled = sum((lambda .0: for panel in .0:
  441. panel.Size.height)(self.expandopanels))
  442.         if self.capbar.Shown:
  443.             filled += self.capbar.Size.height
  444.         
  445.         if self.eheader.Shown:
  446.             filled += self.eheader.Size.height
  447.         
  448.         maxheight = Monitor.GetFromWindow(wx.FindWindowByName('Buddy List')).ClientArea.height * pref('infobox.ratio_to_screen', 0.75)
  449.         if self.elist.Shown:
  450.             content = self.elist
  451.             desired = content.GetFullHeight()
  452.         elif self.cpanel.Shown:
  453.             content = self.profilebox
  454.             content.SetSize(wx.Size(width, 1))
  455.             desired = content.VirtualSize.height + 16
  456.         elif self.errorpanel.Show:
  457.             content = self.errorpanel
  458.             desired = content.MinSize.height
  459.         
  460.         allotted = min(desired + filled, maxheight)
  461.         if getattr(self.account, 'service', None) == 'twitter':
  462.             allotted = maxheight
  463.         
  464.         contentsize = None if isinstance(content, EmailList) and allotted == maxheight else allotted - filled
  465.         content.SetSize(wx.Size(width, contentsize))
  466.         sz = Size(width + self.framesize.left + self.framesize.right, contentsize + filled + self.framesize.top + self.framesize.bottom)
  467.         if getattr(self, '_resizingto', None) != sz and pref('infobox.animation.resizing', False):
  468.             resize_smoothly(self, sz)
  469.             self._resizingto = sz
  470.         else:
  471.             self.Size = sz
  472.         self.panel.SetSize(sz)
  473.         wx.CallAfter(self.panel.Layout)
  474.         wx.CallAfter(self.cpanel.Layout)
  475.         if hasattr(self, 'bg') and isinstance(self.bg, SplitImage4):
  476.             ApplySmokeAndMirrors(self, self.bg.GetBitmap(self.Size))
  477.         else:
  478.             ApplySmokeAndMirrors(self)
  479.  
  480.     
  481.     def DelayedHide(self):
  482.         if not self.hidingtimer:
  483.             self.hidingtimer = CallLater(1000, self.DoDelayedHide)
  484.         
  485.  
  486.     
  487.     def DoDelayedHide(self):
  488.         self.hidingtimer = None
  489.         if not self.Rect.Contains(GetMousePosition()):
  490.             self.Hide()
  491.         
  492.  
  493.     
  494.     def Hide(self):
  495.         if self.hidingtimer:
  496.             self.hidingtimer.Stop()
  497.             self.hidingtimer = None
  498.         
  499.         if self.showingtimer.IsRunning():
  500.             self.showingtimer.Stop()
  501.         
  502.         if self.traytimer.IsRunning():
  503.             self.traytimer.Stop()
  504.         
  505.         self.Show(False)
  506.  
  507.     
  508.     def DoubleclickHide(self):
  509.         self._doubleclickhide = True
  510.         self.Hide()
  511.  
  512.     
  513.     def InvalidateDoubleclickHide(self):
  514.         self._doubleclickhide = False
  515.  
  516.     
  517.     def DrawCrap(self, c1, c2, mp):
  518.         tan = tan
  519.         radians = radians
  520.         import math
  521.         DX = abs(c1.x - mp.x)
  522.         LA = self.min_angle_of_entry
  523.         HA = self.max_angle_of_entry
  524.         minDY = int(abs(tan(radians(LA)) * DX))
  525.         maxDY = int(abs(tan(radians(HA)) * DX))
  526.         DY1 = min(max(abs(c1.y - mp.y), minDY), maxDY)
  527.         DY2 = min(max(abs(c2.y - mp.y), minDY), maxDY)
  528.         AP1 = Point(c1.x, mp.y - DY1)
  529.         AP2 = Point(c1.x, mp.y + DY2)
  530.         sdc = wx.ScreenDC()
  531.         sdc.SetBrush(wx.Brush(wx.Color(0, 255, 0, 125)))
  532.         sdc.SetPen(wx.Pen(wx.Color(0, 0, 255, 255)))
  533.         sdc.DrawPolygon((AP1, AP2, mp))
  534.         sdc.Pen = wx.RED_PEN
  535.         sdc.DrawLinePoint(mp, c1)
  536.         sdc.DrawLinePoint(mp, c2)
  537.  
  538.     
  539.     def StateChanged(self, *a):
  540.         wx.CallAfter(self._StateChanged, *a)
  541.  
  542.     
  543.     def _StateChanged(self, *a):
  544.         account = self.account
  545.         online = account.state in (account.Statuses.ONLINE, account.Statuses.CHECKING)
  546.         issocnet = isinstance(account, SocialNetwork)
  547.         isemail = isinstance(account, EmailAccount)
  548.         self.capbar.Show(False)
  549.         if issocnet:
  550.             pass
  551.         self.cpanel.Show(online)
  552.         self.eheader.SetAccount(account)
  553.         self.eheader.Show(True)
  554.         if isemail and online:
  555.             self.elist.SetAccount(account)
  556.         else:
  557.             self.elist.Show(False)
  558.         if issocnet and online and account.dirty:
  559.             self.InfoSync()
  560.         
  561.         if account.state == account.Statuses.OFFLINE:
  562.             pass
  563.         active = account.offline_reason == account.Reasons.WILL_RECONNECT
  564.         if active:
  565.             
  566.             message = lambda : profile.account_manager.state_desc(account)
  567.         elif not online or profile.account_manager.state_desc(account):
  568.             pass
  569.         
  570.         message = None
  571.         error_link = account.error_link()
  572.         if error_link is None:
  573.             self.errorpanel.Error(message)
  574.         else:
  575.             (link, cb) = error_link
  576.             self.errorpanel.Error(message, link, cb)
  577.  
  578.     
  579.     def BuddyListItem(self):
  580.         return None if self.metacontact else self.account
  581.  
  582.     BuddyListItem = property(BuddyListItem)
  583.     
  584.     def SelectNext(self):
  585.         mc = self.metacontact
  586.         if mc:
  587.             i = mc.index(self.account) + 1
  588.             l = len(mc)
  589.             if i >= l:
  590.                 i -= l
  591.             
  592.             self.SelectContact(mc[i])
  593.         
  594.         for panel in self.expandopanels:
  595.             panel.Refresh()
  596.         
  597.  
  598.     
  599.     def SelectLast(self):
  600.         mc = self.metacontact
  601.         if mc:
  602.             i = mc.index(self.account) - 1
  603.             self.SelectContact(mc[i])
  604.         
  605.         for panel in self.expandopanels:
  606.             panel.Refresh()
  607.         
  608.  
  609.     
  610.     def MetaContactObserver(self, obj, attr, old, new):
  611.         wx.CallAfter(self._MetaContactObserver, obj, attr, old, new)
  612.  
  613.     
  614.     def _MetaContactObserver(self, obj, attr, old, new):
  615.         if wx.IsDestroyed(self):
  616.             warnings.warn('Infobox is dead but is still getting notified from MetaContactOberver')
  617.             return None
  618.         
  619.         if self.account not in self.metacontact or not (self.Shown):
  620.             
  621.             try:
  622.                 self.account = self.metacontact.first_online
  623.             except AttributeError:
  624.                 err = ''.join([
  625.                     'The obj: ',
  626.                     str(obj),
  627.                     '\nThe attr: ',
  628.                     attr,
  629.                     '\nold -> new: ',
  630.                     str(old),
  631.                     '->',
  632.                     str(new),
  633.                     '\n\nThe Metacontact: ',
  634.                     str(self.metacontact)])
  635.                 log.error(err)
  636.             except:
  637.                 None<EXCEPTION MATCH>AttributeError
  638.             
  639.  
  640.         None<EXCEPTION MATCH>AttributeError
  641.         self.Repanelmater()
  642.         self.Reposition()
  643.  
  644.     
  645.     def ContactObserver(self, obj, attr, old, new):
  646.         wx.CallAfter(self._ContactObserver, obj, attr, old, new)
  647.  
  648.     
  649.     def _ContactObserver(self, obj, attr, old, new):
  650.         self.InfoSync()
  651.         for panel in self.expandopanels:
  652.             panel.Refresh()
  653.         
  654.  
  655.     
  656.     def Display(self, pl, pr, caller, force_corner = False, force_change = False):
  657.         
  658.         try:
  659.             self.hidingtimer.Stop()
  660.             self.hidingtimer = None
  661.         except AttributeError:
  662.             pass
  663.  
  664.         if self._doubleclickhide and caller is self.BuddyListItem:
  665.             return None
  666.         
  667.         if not pl == self.pl and pr == self.pr and caller is self.metacontact or caller is self.account:
  668.             if hasattr(self, 'pausedover'):
  669.                 self.pausedover.Stop()
  670.             
  671.             mp = GetMousePosition()
  672.             rect = self.Rect
  673.             onleft = rect.x < mp.x
  674.             if self.Shown:
  675.                 if not force_change:
  676.                     pass
  677.                 if not force_corner:
  678.                     lp = getattr(self, 'LastMousePoint', mp)
  679.                     dp = mp - lp
  680.                     lmd = getattr(self, 'LastMouseDirection', [
  681.                         False,
  682.                         False])
  683.                     d = self.LastMouseDirection = (None, None if dp.x else lmd[0] if dp.y else lmd[1])
  684.                     c1 = rect.Position
  685.                     c2 = c1 + wx.Point(0, rect.height)
  686.                     if pref('infobox.tracelines', False):
  687.                         self.DrawCrap(c1, c2, mp)
  688.                     
  689.                     if (d[0] or not onleft or not d[0]) and onleft:
  690.                         c = None if d[1] else c1
  691.                         am = (vector(*lp) - vector(*mp)).angle
  692.                         ac = max(min((vector(*lp) - vector(*c)).angle, self.max_angle_of_entry), self.min_angle_of_entry)
  693.                         if am < ac and mp.y > c1.y and mp.y < c2.y:
  694.                             self.LastMousePoint = None + mp if onleft else (-1, 0)
  695.                             self.pausedover = None((None, None, None, CallLater, self.pause_time), (lambda : None if self.FriendlyTouch(mp) else None))
  696.                             return None
  697.                         
  698.                     
  699.                 
  700.             self.LastMousePoint = None + mp(*wx.Point if onleft else (-1, 0))
  701.             if isinstance(self.account, SocialNetwork):
  702.                 self.errorpanel.Error()
  703.                 
  704.                 try:
  705.                     self.account.unobserve_count(self.InfoSync)
  706.                 except NotImplementedError:
  707.                     pass
  708.  
  709.                 
  710.                 try:
  711.                     n = self.account.remove_observer(self.StateChanged, 'state')
  712.                 except NotImplementedError:
  713.                     pass
  714.                 except:
  715.                     None<EXCEPTION MATCH>NotImplementedError
  716.                 
  717.  
  718.             None<EXCEPTION MATCH>NotImplementedError
  719.             if isinstance(self.account, EmailAccount):
  720.                 self.errorpanel.Error()
  721.                 n = self.account.remove_observer(self.StateChanged, 'state')
  722.             elif isinstance(self.account, Contact):
  723.                 if self.metacontact:
  724.                     if hasattr(self, 'metacontact_observer'):
  725.                         self.metacontact_observer.disconnect()
  726.                         del self.metacontact_observer
  727.                     else:
  728.                         log.warning("unobserving a MetaContact, but didn't have a metacontact_observer")
  729.                 else:
  730.                     n = self.account.remove_observer(self.ContactObserver, 'status', 'status_message', 'idle', 'icon')
  731.             
  732.             self.pl = pl
  733.             self.pr = pr
  734.             if force_corner != self.force_corner:
  735.                 self.Show(False)
  736.             
  737.             self.force_corner = force_corner
  738.             if isinstance(caller, (Contact, MetaContact)):
  739.                 self.eheader.Show(False)
  740.                 self.elist.Show(False)
  741.                 self.capbar.Show(True)
  742.                 self.cpanel.Show(True)
  743.                 if isinstance(caller, MetaContact):
  744.                     metacontact = caller
  745.                     contact = caller.first_online
  746.                 else:
  747.                     metacontact = []
  748.                     contact = caller
  749.                 if not self.IsShown() and metacontact != self.metacontact or contact is not self.account:
  750.                     if metacontact:
  751.                         pass
  752.                     elif True:
  753.                         self.metacontact = metacontact
  754.                         self.account = contact
  755.                     
  756.                 if metacontact:
  757.                     self.metacontact_observer = metacontact.add_list_observer(self.MetaContactObserver, self.ContactObserver, 'status', 'status_message', 'idle', 'icon')
  758.                 else:
  759.                     contact.add_observer(self.ContactObserver, 'status', 'status_message', 'idle', 'icon')
  760.                 if self.account is not None:
  761.                     caps = self.capbar
  762.                     if isinstance(self.account, MetaContact):
  763.                         buddies = self.account
  764.                         name = buddies.alias
  765.                     else:
  766.                         buddies = [
  767.                             self.account]
  768.                         name = self.account.name
  769.                     if any((lambda .0: for b in .0:
  770. b.blocked)(buddies)):
  771.                         content = _('Unblock %s')
  772.                     else:
  773.                         content = _('Block %s')
  774.                     caps.iblock.content = [
  775.                         content % name]
  776.                 
  777.             elif isinstance(caller, EmailAccount):
  778.                 self.metacontact = []
  779.                 self.account = caller
  780.                 self.account.add_observer(self.StateChanged, 'state')
  781.                 self._StateChanged()
  782.             elif isinstance(caller, SocialNetwork):
  783.                 self.metacontact = []
  784.                 self.account = caller
  785.                 
  786.                 try:
  787.                     self.account.observe_count(self.InfoSync)
  788.                 except NotImplementedError:
  789.                     pass
  790.  
  791.                 
  792.                 try:
  793.                     self.account.add_observer(self.StateChanged, 'state')
  794.                 except NotImplementedError:
  795.                     pass
  796.  
  797.                 self._StateChanged()
  798.             
  799.             self.Repanelmater()
  800.             self.Reposition()
  801.         
  802.         if not self.IsShown():
  803.             if force_corner:
  804.                 fadein(self, 'xfast')
  805.                 self.traytimer.Start(TRAY_TIMER_MS)
  806.             elif self.quickshow:
  807.                 self.ShowOnScreen()
  808.             elif not self.showingtimer.IsRunning() or self.account is not self.showingtimer.contact:
  809.                 self.showingtimer.Start(self.account)
  810.             
  811.             if not force_corner and not self.mouseouttimer.IsRunning():
  812.                 self.mouseouttimer.Start()
  813.             
  814.         
  815.  
  816.     
  817.     def ShowOnScreen(self):
  818.         self.ShowNoActivate(True)
  819.         if 'wxMSW' in wx.PlatformInfo:
  820.             show_on_top(self)
  821.         
  822.  
  823.     
  824.     def OnSize(self, event):
  825.         event.Skip()
  826.         if self.pl and self.pr:
  827.             if self.ScreenRect.Contains(wx.GetMousePosition()):
  828.                 wx.CallLater(250, self.Reposition)
  829.             else:
  830.                 self.Reposition()
  831.         
  832.         self.Refresh()
  833.  
  834.     
  835.     def Reposition(self):
  836.         pl = self.pl
  837.         pr = self.pr
  838.         force_corner = self.force_corner
  839.         size = self.Size
  840.         if not force_corner:
  841.             p1 = None if self.right_of_list else pr
  842.             p2 = None if self.right_of_list else (pl[0] - self.Size.width, pl[1])
  843.             p2rect = RectPS(wx.Point(*p2), wx.Size(*size))
  844.             screenrect = None(Monitor.GetFromRect(RectPS if self.right_of_list else pl, size)).ClientArea
  845.             offscreen = None if self.right_of_list else p2rect.left < screenrect.left
  846.             pos = None if offscreen else p2
  847.             direction = wx.TOP | wx.BOTTOM
  848.         else:
  849.             pos = (force_corner - Point(*size)) + Point(1, 1)
  850.             direction = wx.TOP | wx.BOTTOM | wx.LEFT | wx.RIGHT
  851.         r = wx.RectPS(wx.Point(*pos), wx.Size(*size))
  852.         screenrect = Monitor.GetFromRect(r).ClientArea
  853.         pos = screenrect.Clamp(r, direction).Position
  854.         if not force_corner and self.animate and self.Shown:
  855.             if self.animation_method == 2:
  856.                 if getattr(self, '_moving_to', None) != pos:
  857.                     self.animationtimer = move_smoothly(self, pos, time = self.animation_time, interval = self.animation_interval)
  858.                 
  859.             else:
  860.                 self.animationtimer = self.SlideTo(pos)
  861.         elif self.animationtimer:
  862.             self.animationtimer.stop()
  863.             self.animationtimer = None
  864.         
  865.         self.SetPosition(pos)
  866.         if force_corner:
  867.             self.traytimer.Start(TRAY_TIMER_MS)
  868.         
  869.         self._moving_to = pos
  870.  
  871.     animation_time = prefprop('infobox.animation.time', 200)
  872.     animation_interval = prefprop('infobox.animation.interval', 10)
  873.     animation_method = prefprop('infobox.animation.method', 1)
  874.     animate = prefprop('infobox.animate', False)
  875.     right_of_list = prefprop('infobox.right_of_list', True)
  876.     max_angle_of_entry = prefprop('infobox.max_angle_of_entry', 60)
  877.     min_angle_of_entry = prefprop('infobox.max_angle_of_entry', 30)
  878.     pause_time = prefprop('infobox.pause_time', 250)
  879.     width = prefprop('infobox.width', DEFAULT_INFOBOX_WIDTH)
  880.     
  881.     def on_synctimer(self):
  882.         t = self.synctimer
  883.         t.Stop()
  884.         if t.needs_sync:
  885.             t.needs_sync = False
  886.             self.InfoSync()
  887.         
  888.  
  889.     
  890.     def InfoSync(self, *a):
  891.         if not hasattr(self, 'synctimer'):
  892.             self.synctimer = wx.PyTimer(self.on_synctimer)
  893.             self.synctimer.needs_sync = False
  894.         
  895.         if self.synctimer.IsRunning():
  896.             self.synctimer.needs_sync = True
  897.             return None
  898.         
  899.         pb = self.profilebox
  900.         cpanel = self.cpanel
  901.         self.Frozen().__enter__()
  902.         
  903.         try:
  904.             if cpanel.IsShown():
  905.                 if self.capbar.Shown:
  906.                     self.capbar.ApplyCaps(self.account)
  907.                 
  908.                 
  909.                 try:
  910.                     pfile = self.FillInProfile()
  911.                 except Exception:
  912.                     traceback.print_exc()
  913.                     pfile = _(u'Error generating content')
  914.  
  915.                 pb._page = pfile
  916.                 
  917.                 pb.GetPage = lambda : pb._page
  918.                 pb.SetPage(pfile)
  919.             
  920.             self.DoSizeMagic()
  921.         finally:
  922.             pass
  923.  
  924.         self.synctimer.StartOneShot(300)
  925.  
  926.     
  927.     def Repanelmater(self):
  928.         panelsneeded = len(self.metacontact)
  929.         exp = self.expandopanels
  930.         sz = self.cpanel.Sizer
  931.         if panelsneeded > 0:
  932.             while len(exp) < panelsneeded:
  933.                 panel = ExpandoPanel(self.cpanel, self)
  934.                 exp.insert(0, panel)
  935.                 sz.Insert(0, panel, 0, wx.EXPAND)
  936.             while len(exp) > panelsneeded:
  937.                 panel = exp[0]
  938.                 panel.Show(False)
  939.                 exp.remove(panel)
  940.                 sz.Detach(panel)
  941.                 panel.Destroy()
  942.         else:
  943.             for panel in exp[:]:
  944.                 panel.Show(False)
  945.                 exp.remove(panel)
  946.                 sz.Detach(panel)
  947.                 panel.Destroy()
  948.             
  949.         self.cpanel.Refresh()
  950.         self.InfoSync()
  951.  
  952.     
  953.     def SelectContact(self, contact):
  954.         self.account = contact
  955.         self.InfoSync()
  956.  
  957.     
  958.     def FillInProfile(self):
  959.         acct = self.account
  960.         
  961.         try:
  962.             ibp = IInfoboxHTMLProvider(acct)
  963.         except protocols.AdaptationFailure:
  964.             pass
  965.  
  966.         if ibp._dirty or acct not in self._cache:
  967.             self._cache[acct] = ibp.get_html(self.htmlfonts)
  968.         
  969.         return self._cache[acct]
  970.         if isinstance(acct, SocialNetwork):
  971.             cachekey = acct
  972.             if getattr(acct, 'header_tabs', False):
  973.                 currtab = acct._current_tab
  974.                 cachekey = (acct, currtab)
  975.                 dirty = acct._dirty[currtab]
  976.             elif getattr(acct, '_dirty', False):
  977.                 cachekey = acct
  978.                 dirty = True
  979.             else:
  980.                 dirty = False
  981.             if dirty or cachekey not in self._cache:
  982.                 print 'Regenerating profile for %r' % acct
  983.                 self._cache[cachekey] = linkify(self.make_format(cachekey))
  984.                 if getattr(acct, 'header_tabs', False):
  985.                     acct._dirty[cachekey[1]] = False
  986.                 else:
  987.                     acct._dirty = False
  988.                 self._cache[cachekey] = ''.join((lambda .0: for y in .0:
  989. y.strip())(self._cache[cachekey].split('\n')))
  990.             
  991.             return self._cache[cachekey]
  992.         elif isinstance(acct, EmailAccount):
  993.             import sys
  994.             print >>sys.stderr, 'WARNING: FillInProfile called with an email account'
  995.         else:
  996.             
  997.             try:
  998.                 return GetInfo(acct, pref('infobox.showprofile', False))
  999.             except Exception:
  1000.                 print_exc()
  1001.                 return ''
  1002.  
  1003.  
  1004.     
  1005.     def memo_format(self, cachekey):
  1006.         if isinstance(cachekey, tuple):
  1007.             acct = cachekey[0]
  1008.             return format(self.format[acct.service][cachekey[1]], acct, self.htmlfonts)
  1009.         else:
  1010.             acct = cachekey
  1011.             return format(self.format[acct.service], acct, self.htmlfonts)
  1012.  
  1013.     
  1014.     def make_format(self, cachekey, obj = None, data = None):
  1015.         if isinstance(cachekey, tuple):
  1016.             acct = cachekey[0]
  1017.         else:
  1018.             acct = cachekey
  1019.         if acct.service not in ('digsby', 'facebook', 'myspace', 'twitter'):
  1020.             import warnings
  1021.             warnings.warn("Don't know how to make an infobox for %r" % acct)
  1022.             return _(u'No additional information')
  1023.         
  1024.         return self.memo_format(cachekey)
  1025.  
  1026.     
  1027.     def OnLinkClicked(self, event):
  1028.         href = event.GetLinkInfo().GetHref()
  1029.         should_not_hide = False
  1030.         None if href == '#profile' else None<EXCEPTION MATCH>Exception
  1031.         wx.CallAfter(wx.LaunchDefaultBrowser, href)
  1032.         if pref('infobox.hide_on_click', True):
  1033.             if not should_not_hide:
  1034.                 self.Hide()
  1035.             
  1036.         
  1037.  
  1038.     
  1039.     def Befriend(self, friend):
  1040.         self.friends.add(friend)
  1041.  
  1042.     
  1043.     def Defriend(self, friend):
  1044.         self.friends.discard(friend)
  1045.  
  1046.     
  1047.     def FriendlyTouch(self, mp = None):
  1048.         windowatpointer = FindWindowAtPointer()
  1049.         for friend in self.friends:
  1050.             if friend and windowatpointer is friend:
  1051.                 if isinstance(friend, BuddyList):
  1052.                     if not mp:
  1053.                         pass
  1054.                 None if not friend.ClientRect.Contains(friend.Parent.ScreenToClient(GetMousePosition())) and GetMouseState().LeftDown() else GetMouseState().LeftDown()
  1055.                 return True
  1056.                 continue
  1057.         
  1058.         return False
  1059.  
  1060.  
  1061. from copy import deepcopy as copy
  1062. from util import curly, get
  1063.  
  1064. def format(fmt, obj, htmlfonts, data = None):
  1065.     if data is None:
  1066.         data = []
  1067.         return_str = True
  1068.     else:
  1069.         return_str = False
  1070.     mysentinel = Sentinel()
  1071.     
  1072.     sget = lambda o, k: get(o, k, mysentinel)
  1073.     mydata = []
  1074.     mydata_append = mydata.append
  1075.     order = get(fmt, 'order', fmt.keys())
  1076.     curlylocals = copy(fmt)
  1077.     curlylocals['fonts'] = htmlfonts
  1078.     curlylocals['TagFont'] = TagFont
  1079.     for key in order:
  1080.         fmtval = sget(fmt, key)
  1081.         objval = sget(obj, key)
  1082.         if not objval and get(fmtval, 'hide_empty', False):
  1083.             continue
  1084.         
  1085.         if mysentinel in (fmtval, objval):
  1086.             continue
  1087.             continue
  1088.         if isinstance(objval, list):
  1089.             hdr = curly(get(fmtval, 'header', ''), source = curlylocals)
  1090.             sep = curly(get(fmtval, 'separator', ''), source = curlylocals)
  1091.             ftr = curly(get(fmtval, 'footer', ''), source = curlylocals)
  1092.             mydata.append(hdr)
  1093.             if not objval:
  1094.                 curlylocals['obj'] = obj
  1095.                 mydata_append(curly(get(fmtval, 'none', ''), source = curlylocals))
  1096.             else:
  1097.                 for thing in objval:
  1098.                     type_d = get(fmtval, type(thing).__name__, { })
  1099.                     if not type_d:
  1100.                         continue
  1101.                     
  1102.                     mydata_append(sep)
  1103.                     mydata_append(make_icon_str(get(type_d, 'icon', '')))
  1104.                     curlylocals['obj'] = thing
  1105.                     mesgstr = get(type_d, 'message', '')
  1106.                     mydata_append(curly(mesgstr, source = curlylocals))
  1107.                 
  1108.                 mydata_append(sep)
  1109.             mydata_append(ftr)
  1110.             continue
  1111.         if isinstance(fmtval, dict):
  1112.             format(fmtval, objval, htmlfonts, mydata)
  1113.             continue
  1114.         if not objval:
  1115.             continue
  1116.         
  1117.         curlylocals['obj'] = obj
  1118.         mydata_append(curly(fmtval, source = curlylocals))
  1119.     
  1120.     if len(mydata) == 0:
  1121.         curlylocals['obj'] = obj
  1122.         mydata_append(curly(get(fmt, 'none', ''), source = curlylocals))
  1123.     
  1124.     mydata = make_header(fmt, curlylocals) + mydata + make_footer(fmt, curlylocals)
  1125.     data.extend(mydata)
  1126.     if return_str:
  1127.         return ''.join(data)
  1128.     else:
  1129.         return data
  1130.  
  1131.  
  1132. def make_icon_str(s):
  1133.     if not s:
  1134.         return ''
  1135.     
  1136.     s = s[5:]
  1137.     sent = object()
  1138.     return '<wxp module="gui.infobox.htmlbitmaps"class="BitmapFromSkin" width ="99%%" height="-1"><param name="key" value="%s"></wxp>' % s
  1139.  
  1140.  
  1141. def make_header(fmt, obj):
  1142.     return [ curly(get(fmt, k, ''), source = obj) for k in ('header', 'separator') ]
  1143.  
  1144.  
  1145. def make_footer(fmt, obj):
  1146.     return [ curly(get(fmt, k, ''), source = obj) for k in ('separator', 'footer') ]
  1147.  
  1148. if 'wxMSW' in wx.PlatformInfo:
  1149.     from gui.native.win.winconstants import HWND_TOPMOST, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_SHOWWINDOW
  1150.     WINDOWPOS_FLAGS = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW
  1151.     from ctypes import windll
  1152.     SetWindowPos = windll.user32.SetWindowPos
  1153.     
  1154.     def show_on_top(win):
  1155.         SetWindowPos(win.Handle, HWND_TOPMOST, 0, 0, 0, 0, WINDOWPOS_FLAGS)
  1156.  
  1157.  
  1158. import gui.input as gui
  1159. gui.input.add_class_context(_('InfoBox'), 'InfoBox', cls = InfoBox)
  1160.